package co.edu.javeriana.aes.patrones.monopolio.net;

import co.edu.javeriana.aes.patrones.monopolio.message.Message;
import co.edu.javeriana.aes.patrones.monopolio.util.exception.MonopolyException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 
 * @author gersua
 */
public abstract class NetworkConnection extends Thread {

    private ObjectInputStream ois;
    private ObjectOutputStream oos;
    private Socket socket;
    private boolean stopConnection = false;
    private Receiver receiver;
    private Forwarder forwarder;

    public NetworkConnection(Socket socket) throws MonopolyException {
        this.socket = socket;

        try {
            oos = new ObjectOutputStream(socket.getOutputStream());
        } catch (IOException ex) {
            throw new MonopolyException("Error while creating OutputStream.", ex);
        }

        try {
            ois = new ObjectInputStream(socket.getInputStream());
        } catch (IOException ex) {
            throw new MonopolyException("Error while creating InputStream.", ex);
        }

        receiver = new Receiver();
        forwarder = new Forwarder();

        start();
        receiver.start();
    }

    @Override
    public void run() {
        while (!stopConnection);
    }

    public String getRemoteHost() {
        return socket.getRemoteSocketAddress().toString();
    }

    public abstract void handleMessage(Message message);

    private void readMessage(Message message) {
        handleMessage(message);
    }

    public void sendMessage(Message message) {
        forwarder.writeMessage(message);
    }

    //<editor-fold defaultstate="collapsed" desc="close">
    public void close() {
        stopConnection = true;
        try {
            socket.shutdownInput();
        } catch (IOException ex) {
            Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            ois.close();
        } catch (IOException ex) {
            Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            socket.shutdownOutput();
        } catch (IOException ex) {
            Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            oos.close();
        } catch (IOException ex) {
            Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            socket.close();
        } catch (IOException ex) {
            Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    //</editor-fold>

    private class Receiver extends Thread {

        @Override
        public void run() {
            while (!stopConnection) {
                try {
                    Message message = (Message) ois.readObject();
                    readMessage(message);
                } catch (IOException ex) {
                    Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private class Forwarder {

        public void writeMessage(Message message) {
            try {
                oos.writeObject(message);
            } catch (IOException ex) {
                Logger.getLogger(NetworkConnection.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}